package com.mifengkong.frtools.http.request.interceptor;


import android.support.annotation.NonNull;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.mifengkong.frtools.util.FRBaseAESUtil;
import com.mifengkong.frtools.util.FRLog;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.Set;

import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;

/**
 * Created by jiangyongxing on 2018/2/1.
 * 描述：加密接口
 */

public class EncryptInterceptor implements Interceptor {

    private String passwordKey;

    public EncryptInterceptor(String passwordKey) {
        this.passwordKey = passwordKey;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        RequestBody body = request.body();
        Headers headers = request.headers();
        Response originalResponse = null;

        if ("POST".equalsIgnoreCase(request.method()) && null != body) {
            RequestBody newBody = null;
            if (body instanceof FormBody) {
                newBody = encryptParamsToFormBody((FormBody) body);
            } else if (body instanceof MultipartBody) {
                newBody = encryptParamsToMultipartBody((MultipartBody) body);
            }
            if (null != newBody) {
                Request.Builder builder = request.newBuilder()
                        .url(request.url())
                        .headers(headers)
                        .method(request.method(), newBody);
                Request newRequest = builder.build();
                originalResponse = chain.proceed(newRequest);
            }
        } else if ("GET".equalsIgnoreCase(request.method())) {
            HttpUrl httpUrl = request.url();
            Request.Builder requestBuilder = request.newBuilder().headers(headers);
            HttpUrl.Builder httpUrlBuilder = encryptParamsToGetUrl(httpUrl);
            requestBuilder.url(httpUrlBuilder.build());
            originalResponse = chain.proceed(requestBuilder.build());
        }

        if (null == originalResponse) {
            originalResponse = chain.proceed(request);
        }
        originalResponse = decryptData(originalResponse);
        return originalResponse;
    }

    /**
     * 对body中的数据进行解密
     *
     * @param originalResponse
     */
    private Response decryptData(Response originalResponse) throws IOException {
        ResponseBody responseBody = originalResponse.body();
        Charset chartSet = Charset.forName("UTF-8");
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            chartSet = contentType.charset(chartSet);
        }
        BufferedSource bufferedSource = responseBody.source();
        bufferedSource.request(Long.MAX_VALUE);
        Buffer buffer = bufferedSource.buffer();
        String body = buffer.clone().readString(chartSet);
        try {
            JSONObject jsonObject = new JSONObject(body);
            String dataStr = jsonObject.getString("data");
            String decrypyStr = FRBaseAESUtil.decrypt(dataStr, passwordKey);
            FRLog.e("urllink", decrypyStr);
            try {
                JSONObject dataJson = new JSONObject(decrypyStr);
                jsonObject.put("data", dataJson);
            } catch (Exception e) {
                try {
                    JSONArray dataJson = new JSONArray(decrypyStr);
                    jsonObject.put("data", dataJson);
                } catch (Exception e1) {

                }
            }
            originalResponse = originalResponse.newBuilder().body(ResponseBody.create(null, jsonObject.toString())).build();
        } catch (JSONException e) {
            originalResponse = originalResponse.newBuilder().body(ResponseBody.create(null, body)).build();
            e.printStackTrace();
        }
        return originalResponse;
    }

    /**
     * 对get方法中的参数进行加密
     *
     * @param httpUrl
     * @return
     */
    @NonNull
    private HttpUrl.Builder encryptParamsToGetUrl(HttpUrl httpUrl) {
        HttpUrl.Builder httpUrlBuilder = new HttpUrl.Builder().scheme(httpUrl.scheme()).host(httpUrl.host());
        List<String> pathSegments = httpUrl.pathSegments();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < pathSegments.size(); i++) {
            sb.append(pathSegments.get(i));
            if (i != pathSegments.size() - 1) {
                sb.append("/");
            }
        }
        httpUrlBuilder.addEncodedPathSegments(sb.toString());

        Map<String, String> parmas = new ArrayMap<>();
        Set<String> name = httpUrl.queryParameterNames();
        for (String s : name) {
            parmas.put(s, httpUrl.queryParameter(s));
        }
        String encryptData = encryptParmas(parmas);
        httpUrlBuilder.addQueryParameter("data", encryptData);
        return httpUrlBuilder;
    }

    /**
     * 将map中的数据转成json  并且进行加密
     *
     * @param parmas
     * @return
     */
    private String encryptParmas(Map<String, String> parmas) {
        Gson gson = new Gson();
        String jsonData = gson.toJson(parmas);
        String encryptStr = FRBaseAESUtil.encrypt(jsonData, passwordKey);
        return encryptStr;
    }

    /**
     * 对post方法中的参数进行加密
     *
     * @param body
     * @return
     */
    private FormBody encryptParamsToFormBody(FormBody body) {
        FormBody.Builder builder = new FormBody.Builder();
        Map<String, String> parmas = new ArrayMap<>();
        int paramSize = body.size();
        if (paramSize > 0) {
            for (int i = 0; i < paramSize; i++) {
                parmas.put(body.name(i), body.value(i));
            }
        }
        String encryptStr = encryptParmas(parmas);
        builder.add("data", encryptStr);
        return builder.build();
    }

    /**
     * 对大文本中的方法中的参数进行加密
     *
     * @param body
     * @return
     */
    private MultipartBody encryptParamsToMultipartBody(MultipartBody body) {
        MultipartBody.Builder multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        Map<String, String> parmas = new ArrayMap<>();

        List<MultipartBody.Part> oldParts = body.parts();
        if (oldParts != null && oldParts.size() > 0) {
            for (int i = 0; i < oldParts.size(); i++) {
                MultipartBody.Part part = oldParts.get(i);
                RequestBody requestBody = part.body();
                MediaType mediaType = requestBody.contentType();
                if (null != mediaType) {
                    String type = mediaType.subtype();
                    if (!TextUtils.isEmpty(type) && "form-data".equalsIgnoreCase(type)) {
                        okio.Buffer buffer = new okio.Buffer();
                        try {
                            requestBody.writeTo(buffer);
                            String value = buffer.readString(Charset.forName("UTF-8"));

                            Headers headers = part.headers();
                            Set<String> names = headers.names();
                            for (String name : names) {
                                String headerKey = headers.get(name);
                                if (!TextUtils.isEmpty(headerKey) && headerKey.contains("form-data; name=")) {
                                    String key = headerKey.replace("form-data; name=", "").replace("\"", "");
                                    parmas.put(key, value);
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        multipartBuilder.addPart(part);
                    }
                }
            }
            String encryptData = encryptParmas(parmas);
            multipartBuilder.addFormDataPart("data", null, RequestBody.create(MediaType.parse("multipart/form-data; charset=utf-8"), encryptData));
        }
        return multipartBuilder.build();
    }
}




